package main

import "fmt"

// 使用之前的例子，编写一个在 Request 结构上带有 String() 方法的版本，它能决定服务器如何输出；并使用以下两个请求来测试这个程序：

// req1 := &Request{3, 4, make(chan int)}
// req2 := &Request{150, 250, make(chan int)}
// ...
// // show the output
// fmt.Println(req1,"\n",req2)

type Request struct {
	a, b   int
	replyc chan int
}

type binOp func(int, int) int

func (r *Request) String() string {
	return fmt.Sprintf("%d and %d reply: %d", r.a, r.b, <-r.replyc)
}

func run(op binOp, req *Request) {
	req.replyc <- op(req.a, req.b)
}

func server(op binOp, chanR chan *Request, quit chan bool) {
	for {
		select {
		case req := <-chanR:
			go run(op, req)
		case <-quit:
			return
		}
	}
}

func startServer(op binOp) (chan *Request, chan bool) {
	chanReq := make(chan *Request)
	quit := make(chan bool)
	go server(op, chanReq, quit)
	return chanReq, quit
}

func main() {
	req1 := &Request{3, 4, make(chan int)}
	req2 := &Request{150, 250, make(chan int)}
	chanReq, quit := startServer(func(a, b int) int { return (a + 1) * (b - 1) })
	chanReq <- req1
	chanReq <- req2

	fmt.Println(req1, "\n", req2)
	quit <- true
}
